<!--
 * @Author: anxia.ack anchenkai@come-future.com
 * @Date: 2025-04-21 10:47:34
 * @LastEditors: anxia.ack anchenkai@come-future.com
 * @LastEditTime: 2025-05-07 22:06:08
 * @FilePath: /free-learning/src/views/system/chat-message/index.vue
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<script setup lang="ts">
import MyRate from "@/components/MyRate.vue";
import {
  ref,
  computed,
  onMounted,
  nextTick,
  onUnmounted,
  onBeforeMount,
} from "vue";
import WebSocketManager from "@/utils/websocket";
import { useUserStore } from "@/store";
import {
  getSendChatMessage,
  getReceiveChatMessage,
  sendChatMessage,
  readChatMessage,
  requestDeleteAllChatMessage,
} from "@/api/chat-message";
import type { ChatMessage, ChatMessageDTO } from "@/api/chat-message/type";
import moment from "moment";
import { onBeforeRouteLeave, useRoute } from "vue-router";
import {
  getConsultantInfo,
  type UserExpertiseBO,
  type UserPageVO,
} from "@/api/user";
import { ElMessage, ElMessageBox } from "element-plus";
import { addConsultantReview, type ConsultantReview } from "@/api/consultantReviec";

defineOptions({
  name: "ChatMessageView",
});

interface ChatUser {
  id: number;
  name: string;
  avatar: string;
  lastMessage: string;
  lastTime: string;
  unreadCount: number;
}

const userStore = useUserStore();
const userInfo = computed(() => userStore.userInfo);

const chatUsers = ref<ChatUser[]>([]);
const currentUser = ref<ChatUser | null>(null);
const messages = ref<ChatMessage[]>([]);
const messageContent = ref("");
const scrollbar = ref();
const sendList = ref<ChatMessage[]>([]);
const receiveList = ref<ChatMessage[]>([]);
const consultantInfo = ref<
  UserPageVO & { expertise: UserExpertiseBO[] | undefined }
>();
const userDetailInfo = ref<any>(null);
const loading = ref(false);

// 获取聊天用户列表
const getChatUsers = async () => {
  const [sL, rL] = await Promise.all([
    getSendChatMessage(),
    getReceiveChatMessage(),
  ]);
  sendList.value = sL;
  receiveList.value = rL;
  // 合并发送和接收的消息，按用户分组
  const userMap = new Map<number, ChatUser>();

  [...sL, ...rL].forEach((message) => {
    const isReceiver = message.receiverId === userInfo.value?.userId;
    const userId = isReceiver ? message.senderId : message.receiverId;
    const userName = isReceiver ? message.senderName : message.receiverName;
    const userAvatar = isReceiver
      ? message.senderAvatar
      : message.receiverAvatar;

    if (!userMap.has(userId)) {
      userMap.set(userId, {
        id: userId,
        name: userName,
        avatar: userAvatar,
        lastMessage: message.content,
        lastTime: moment(message.sendTime).format("HH:mm"),
        unreadCount: message.status === 0 && isReceiver ? 1 : 0,
      });
    } else {
      const user = userMap.get(userId)!;
      if (moment(message.sendTime).isAfter(moment(user.lastTime, "HH:mm"))) {
        user.lastMessage = message.content;
        user.lastTime = moment(message.sendTime).format("HH:mm");
      }
      if (message.status === 0 && isReceiver) {
        user.unreadCount++;
      }
    }
  });

  chatUsers.value = Array.from(userMap.values()).sort(
    (a, b) =>
      moment(b.lastTime, "HH:mm").valueOf() -
      moment(a.lastTime, "HH:mm").valueOf()
  );
  console.log(chatUsers.value, "chatUsers");
  console.log(sendList.value, "sendList");
  console.log(receiveList.value, "receiveList");
};

// 选择聊天用户
const handleSelectUser = (user: ChatUser) => {
  currentUser.value = user;

  // 获取与该用户的聊天记录
  const userMessages = [...sendList.value, ...receiveList.value]
    .filter((message) => {
      if (message.receiverId == userInfo.value?.userId) {
        message.status = 1;
      }
      return (
        (message.senderId == userInfo.value?.userId &&
          message.receiverId == user.id) ||
        (message.receiverId == userInfo.value?.userId &&
          message.senderId == user.id)
      );
    })
    .sort(
      (a, b) => moment(a.sendTime).valueOf() - moment(b.sendTime).valueOf()
    );

  if (user.unreadCount > 0) {
    readChatMessage(user.id)
      .then((res) => {
        console.log(res, "标记消息为已读成功");
      })
      .catch((err) => {
        console.error("标记消息为已读失败:", err);
      });
  }
  user.unreadCount = 0;

  messages.value = userMessages;
  scrollToBottom();
};

// 发送消息
const handleSendMessage = async () => {
  if (!messageContent.value.trim() || !currentUser.value) return;

  const message: ChatMessageDTO = {
    id: 0,
    senderId: userInfo.value?.userId!,
    receiverId: currentUser.value.id,
    content: messageContent.value,
    sendTime: moment().format("YYYY-MM-DD HH:mm:ss"),
    status: 0,
    senderName: userInfo.value?.nickname!,
    receiverName: currentUser.value.name,
    senderAvatar: userInfo.value?.avatar!,
    receiverAvatar: currentUser.value.avatar,
    isConsultMessage: true,
  };
  sendList.value.push(message);
  try {
    await sendChatMessage(message);
    if (newMessage.value) {
      await sendChatMessage(newMessage.value);
      newMessage.value = undefined;
    }
    messages.value.push(message);
    messageContent.value = "";
    scrollToBottom();

    // 更新用户列表的最后消息
    const user = chatUsers.value.find((u) => u.id === currentUser.value?.id);
    if (user) {
      user.lastMessage = message.content;
      user.lastTime = moment(message.sendTime).format("HH:mm");
    }
  } catch (error) {
    console.error("发送消息失败:", error);
    // ElMessage.error("发送消息失败");
  }
};

const endConsultDialogVisible = ref(false);
const endConsultForm = ref({
  rating: "",
  reason: "",
});
const handleEndConsult = (hisId: number) => {
  ElMessageBox.confirm("确定要结束咨询吗？结束后消息记录会被清空哦", "提示", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "warning",
  }).then(() => {
    requestDeleteAllChatMessage(hisId).then((res) => {
      getChatUsers();
      messages.value = [];
      endConsultDialogVisible.value = true;
    });
  });
};

// 滚动到底部
const scrollToBottom = async () => {
  await nextTick();
  if (scrollbar.value) {
    const scrollbarDom = scrollbar.value.$el.querySelector(
      ".el-scrollbar__wrap"
    );
    scrollbarDom.scrollTop = scrollbarDom.scrollHeight;
  }
};
const receiveMessage = () => {
  WebSocketManager.subscribeToTopic("/user/queue/chat/message", (message) => {
    try {
      const data: ChatMessageDTO = JSON.parse(message);
      console.log(data, "data");

      const user = chatUsers.value.find((user) => user.id == data.senderId);
      if (
        receiveList.value.map((itme) => itme.sendTime).includes(data.sendTime)
      ) {
        return;
      }
      if (user) {
        user.unreadCount++;
        user.lastMessage = data.content;
        user.lastTime = moment(data.sendTime).format("HH:mm");
      } else {
        chatUsers.value.push({
          id: data.senderId,
          name: data.senderName,
          avatar: data.senderAvatar,
          lastMessage: data.content,
          lastTime: moment(data.sendTime).format("HH:mm"),
          unreadCount: 1,
        });
      }
      if (currentUser.value && currentUser.value?.id == data.senderId) {
        data.status = 1;
        messages.value.push(data);
        readChatMessage(data.senderId).then((res) => {});
        if (user) {
          user.unreadCount = 0;
        }
        scrollToBottom();
      }
      receiveList.value.push(data);
    } catch (error) {
      console.error("处理WebSocket消息失败:", error);
    }
  });
};
const readMessage = () => {
  WebSocketManager.subscribeToTopic(
    "/user/queue/chat/message/read",
    (receiverId) => {
      console.log(receiverId, "receiverId");
      console.log(currentUser.value, "currentUser");
      console.log(chatUsers.value, "chatUsers");
      console.log(sendList.value, "sendList");

      try {
        sendList.value.forEach((message) => {
          if (Number(message.receiverId) === Number(receiverId)) {
            message.status = 1;
          }
        });
      } catch (error) {
        console.error("处理WebSocket消息失败:", error);
      }
    }
  );
};

const deleteAllChatMessage = (hisId: number) => {
  ElMessageBox.confirm(
    "确定要删除所有消息吗（删除后所有消息将无法恢复）？",
    "提示",
    {
      confirmButtonText: "确定",
      cancelButtonText: "取消",
      type: "warning",
    }
  ).then(() => {
    requestDeleteAllChatMessage(hisId).then((res) => {
      console.log(res, "删除所有消息成功");
      getChatUsers();
      messages.value = [];
      currentUser.value = null;
    });
  });
};

const newMessage = ref<ChatMessageDTO>();
const route = useRoute();
onMounted(async () => {
  await getChatUsers();
  receiveMessage();
  readMessage();
  const consultantId = route.query.consultantId;
  if (consultantId) {
    const user = chatUsers.value.find(
      (user) => user.id == Number(consultantId)
    );
    if (user) {
      handleSelectUser(user);
    } else {
      getConsultantInfo(Number(consultantId)).then(async (res) => {
        newMessage.value = {
          id: 0,
          senderId: Number(consultantId),
          receiverId: Number(userInfo.value?.userId!),
          content: `你好，我是咨询师:${res.nickname},毕业于${res.schoolName}${
            res.academicDegreeName
          }学历，擅长处理${res.expertise
            .map((item) => item.expertiseName)
            .join("、")}等问题，有什么可以帮你的吗？`,
          sendTime: moment().format("YYYY-MM-DD HH:mm:ss"),
          status: 1,
          senderName: res.nickname,
          receiverName: userInfo.value?.nickname as string,
          senderAvatar: res.avatar,
          receiverAvatar: userInfo.value?.avatar as string,
          isConsultMessage: true,
        };
        chatUsers.value.unshift({
          id: Number(consultantId),
          name: res.nickname,
          avatar: res.avatar,
          lastMessage: newMessage.value.content,
          lastTime: moment(newMessage.value.sendTime).format("HH:mm"),
          unreadCount: 0,
        });
        receiveList.value.unshift(newMessage.value);
        handleSelectUser(chatUsers.value[0]);
      });
    }
  }
});
onUnmounted(() => {
  currentUser.value = null;
});

const userInfoMap = new Map<
  number,
  UserPageVO & { expertise: UserExpertiseBO[] }
>();
const showUserInfo = async (userId: number) => {
  if (userInfoMap.has(userId)) {
    consultantInfo.value = userInfoMap.get(userId);
    return;
  }
  loading.value = true;
  try {
    const res = await getConsultantInfo(userId);
    userInfoMap.set(userId, res);
    consultantInfo.value = res;
  } catch (error) {
    console.error("获取用户信息失败:", error);
  } finally {
    loading.value = false;
  }
};
const handleConsultColse = () => {
  endConsultDialogVisible.value = false;
};
const handleConfirmConsult = () => {
  const params: Partial<ConsultantReview> = {
    userId: userInfo.value?.userId!,
    consultantId: currentUser.value?.id!,
    rating: Number(endConsultForm.value.rating),
    comment: endConsultForm.value.reason,
    nickName: userInfo.value?.nickname!,
    avatar: userInfo.value?.avatar!,
    consultantName: currentUser.value?.name!,
    reviewTime: moment().format("YYYY-MM-DD HH:mm:ss"),
    status: 0,
  };
  addConsultantReview(params).then((res) => {
    handleConsultColse();
    currentUser.value = null;
    ElMessage.success("评价成功");
  });
};
</script>

<template>
  <div class="chat-container">
    <div class="chat-card">
      <!-- 左侧聊天用户列表 -->
      <div class="chat-users">
        <div class="chat-users__header">
          <h3>消息列表</h3>
        </div>
        <div class="chat-users__list">
          <el-scrollbar>
            <div
              v-for="user in chatUsers"
              :key="user.id"
              class="chat-user-item"
              :class="{ active: currentUser?.id === user.id }"
              @click="handleSelectUser(user)"
            >
              <el-avatar :size="40" :src="user.avatar" />
              <div class="chat-user-info">
                <div class="chat-user-name">{{ user.name }}</div>
                <div class="chat-user-message">{{ user.lastMessage }}</div>
              </div>
              <div class="chat-user-time">{{ user.lastTime }}</div>
              <el-badge
                v-if="user.unreadCount > 0"
                :value="user.unreadCount"
                class="unread-badge"
              />
              <el-icon
                style="cursor: pointer"
                @click="deleteAllChatMessage(user.id)"
              >
                <Delete style="font-size: 12px" />
              </el-icon>
            </div>
          </el-scrollbar>
        </div>
      </div>

      <!-- 右侧聊天内容区 -->
      <div class="chat-content">
        <template v-if="currentUser">
          <div class="chat-content__header" style="text-align: left">
            <span>{{ currentUser.name }}</span>
          </div>
          <div class="chat-content__messages" style="padding-top: 20px">
            <el-scrollbar ref="scrollbar">
              <div
                v-for="message in messages"
                :key="message.id"
                class="message-item"
                :class="{
                  'message-mine': message.senderId === userInfo?.userId,
                }"
              >
                <div class="message-avatar">
                  <el-popover
                    placement="right"
                    :width="300"
                    trigger="click"
                    @show="showUserInfo(message.senderId)"
                    @hide="consultantInfo = undefined"
                  >
                    <template #reference>
                      <el-avatar
                        :size="36"
                        :src="
                          message.senderId === userInfo?.userId
                            ? userInfo?.avatar
                            : message.senderAvatar
                        "
                      />
                    </template>
                    <div class="user-info-card">
                      <el-skeleton :loading="loading" animated>
                        <template #template>
                          <div style="padding: 10px">
                            <div
                              style="
                                display: flex;
                                flex-direction: column;
                                align-items: center;
                                margin-bottom: 15px;
                              "
                            >
                              <el-skeleton-item
                                variant="circle"
                                style="
                                  width: 60px;
                                  height: 60px;
                                  margin-bottom: 10px;
                                "
                              />
                              <el-skeleton-item
                                variant="text"
                                style="width: 100px; height: 20px"
                              />
                            </div>
                            <div style="padding: 0 10px">
                              <div
                                v-for="i in 5"
                                :key="i"
                                style="margin-bottom: 15px"
                              >
                                <el-skeleton-item
                                  variant="text"
                                  style="width: 100%; height: 16px"
                                />
                              </div>
                            </div>
                          </div>
                        </template>
                        <template #default>
                          <template
                            v-if="
                              message.senderId === userInfo?.userId &&
                              userDetailInfo
                            "
                          >
                            <div class="user-info-header">
                              <el-avatar
                                :size="60"
                                :src="userDetailInfo.avatar"
                              />
                              <div class="user-info-name">
                                {{ userDetailInfo.nickname }}
                              </div>
                            </div>
                            <div class="user-info-content">
                              <div class="info-item">
                                <span class="label">手机号：</span>
                                <span>{{ userDetailInfo.mobile }}</span>
                              </div>
                              <div class="info-item">
                                <span class="label">性别：</span>
                                <span>{{
                                  userDetailInfo.gender === 0
                                    ? "保密"
                                    : userDetailInfo.gender === 1
                                    ? "男"
                                    : "女"
                                }}</span>
                              </div>
                              <div class="info-item">
                                <span class="label">邮箱：</span>
                                <span>{{ userDetailInfo.email }}</span>
                              </div>
                              <div class="info-item">
                                <span class="label">学校：</span>
                                <span>{{ userDetailInfo.schoolName }}</span>
                              </div>
                              <div class="info-item">
                                <span class="label">学历：</span>
                                <span>{{
                                  userDetailInfo.academicDegreeName
                                }}</span>
                              </div>
                            </div>
                          </template>
                          <template v-else-if="consultantInfo">
                            <div class="user-info-header">
                              <el-avatar
                                :size="60"
                                :src="consultantInfo.avatar"
                              />
                              <div class="user-info-name">
                                {{ consultantInfo.nickname }}
                              </div>
                            </div>
                            <div class="user-info-content">
                              <div class="info-item">
                                <span class="label">手机号：</span>
                                <span>{{ consultantInfo.mobile }}</span>
                              </div>
                              <div class="info-item">
                                <span class="label">性别：</span>
                                <span>{{
                                  consultantInfo.gender === 0
                                    ? "保密"
                                    : consultantInfo.gender === 1
                                    ? "男"
                                    : "女"
                                }}</span>
                              </div>
                              <div class="info-item">
                                <span class="label">邮箱：</span>
                                <span>{{ consultantInfo.email }}</span>
                              </div>
                              <div class="info-item">
                                <span class="label">学校：</span>
                                <span>{{ consultantInfo.schoolName }}</span>
                              </div>
                              <div class="info-item">
                                <span class="label">学历：</span>
                                <span>{{
                                  consultantInfo.academicDegreeName
                                }}</span>
                              </div>
                              <div
                                v-if="userInfo?.userId == message.receiverId"
                                class="info-item"
                              >
                                <span class="label">擅长领域：</span>
                                <div class="expertise-tags">
                                  <el-tag
                                    v-for="item in consultantInfo.expertise"
                                    :key="item.expertiseCode"
                                    size="small"
                                    class="expertise-tag"
                                  >
                                    {{ item.expertiseName }}
                                  </el-tag>
                                </div>
                              </div>
                            </div>
                          </template>
                        </template>
                      </el-skeleton>
                    </div>
                  </el-popover>
                </div>
                <div class="message-content">
                  <div class="message-info">
                    <span class="message-name">
                      {{
                        message.senderId === userInfo?.userId
                          ? userInfo?.nickname
                          : message.senderName
                      }}
                    </span>
                    <span class="message-time">{{ message.sendTime }}</span>
                  </div>
                  <div
                    :class="{
                      'message-status-end':
                        message.senderId === userInfo?.userId,
                      'message-status-start':
                        message.senderId !== userInfo?.userId,
                    }"
                  >
                    <div class="message-text">{{ message.content }}</div>
                    <div class="message-status">
                      <span
                        v-if="message.status === 0"
                        style="color: #6d6a6a; font-size: 29px"
                        >○</span
                      >
                      <el-icon
                        v-if="message.status === 1"
                        class="message-status-icon"
                      >
                        <CircleCheck />
                      </el-icon>
                    </div>
                  </div>
                </div>
              </div>
            </el-scrollbar>
          </div>
          <div>
            <div class="tool-bar">
              <el-button
                link
                type="danger"
                @click="handleEndConsult(currentUser.id)"
                >结束咨询</el-button
              >
            </div>
            <div class="chat-content__input">
              <el-input
                v-model="messageContent"
                type="textarea"
                :rows="3"
                placeholder="请输入消息内容..."
                @keyup.enter.native="handleSendMessage"
              />
              <el-button type="primary" @click="handleSendMessage"
                >发送</el-button
              >
            </div>
          </div>
        </template>
        <div v-else class="chat-content__empty">
          <el-empty description="选择一个联系人开始聊天" />
        </div>
      </div>
    </div>
    <el-dialog
      v-model="endConsultDialogVisible"
      title="填写评价"
      width="30%"
      @close="handleConsultColse"
    >
      <el-form :model="endConsultForm" label-width="120px">
        <el-form-item label="满意度">
          <MyRate v-model="endConsultForm.rating" :disabled="false"/>
        </el-form-item>
        <el-form-item label="评价此次咨询">
          <el-input
            v-model="endConsultForm.reason"
            type="textarea"
            :rows="3"
            placeholder="请输入评价"
          />
        </el-form-item>
      </el-form>
      <template #footer>
        <div>
          <el-button type="primary" @click="handleConfirmConsult">
            提交
          </el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>

<style lang="scss" scoped>
.chat-container {
  padding: 20px;
  height: calc(100vh - 70px);
  background-color: var(--el-bg-color-page);

  .chat-card {
    height: 100%;
    display: flex;
    background-color: var(--el-bg-color);
    border-radius: 8px;
    box-shadow: var(--el-box-shadow-light);
    overflow: hidden;
  }
}

.chat-users {
  width: 300px;
  border-right: 1px solid var(--el-border-color-lighter);
  display: flex;
  flex-direction: column;

  &__header {
    padding: 20px;
    border-bottom: 1px solid var(--el-border-color-lighter);
    flex-shrink: 0;

    h3 {
      margin: 0;
      font-size: 16px;
      font-weight: 500;
    }
  }

  &__list {
    flex: 1;
    overflow: hidden;
  }
}

.chat-user-item {
  display: flex;
  align-items: center;
  padding: 15px 20px;
  cursor: pointer;
  transition: background-color 0.3s;

  &:hover {
    background-color: #f5f7fa;
  }

  &.active {
    background-color: #f0f2f5;
  }
}

.chat-user-info {
  flex: 1;
  margin-left: 12px;
  overflow: hidden;
}

.chat-user-name {
  font-size: 14px;
  font-weight: 500;
  margin-bottom: 4px;
  color: #000;
  margin-left: 10px;
  text-align: left;
}

.chat-user-message {
  font-size: 12px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: #909399;
  margin-left: 10px;
  text-align: left;
}

.chat-user-time {
  color: #909399;
  font-size: 12px;
}

.unread-badge {
  margin-left: 8px;
}

.chat-content {
  flex: 1;
  display: flex;
  flex-direction: column;

  &__header {
    padding: 20px;
    border-bottom: 1px solid var(--el-border-color-lighter);
    font-size: 16px;
    font-weight: 500;
    flex-shrink: 0;
  }

  &__messages {
    flex: 1;
    overflow: hidden;
    position: relative;
  }

  &__input {
    padding: 20px;
    border-top: 1px solid var(--el-border-color-lighter);
    background-color: var(--el-bg-color);
    flex-shrink: 0;

    .el-button {
      margin-top: 10px;
      float: right;
    }
  }

  &__empty {
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
  }
}

.message-item {
  display: flex;
  margin-bottom: 20px;
  padding: 0 20px;

  &.message-mine {
    flex-direction: row-reverse;

    .message-content {
      margin-right: 12px;
      margin-left: 0;

      .message-info {
        flex-direction: row-reverse;
      }

      .message-text {
        text-align: left;
        background-color: var(--el-color-primary-light-9);
        border-radius: 8px 0 8px 8px;
      }
    }
  }
}

.message-content {
  margin-left: 12px;
  max-width: 60%;
}

.message-info {
  display: flex;
  align-items: center;
  margin-bottom: 4px;
}

.message-name {
  font-size: 14px;
  font-weight: 500;
}

.message-time {
  font-size: 12px;
  color: var(--el-text-color-secondary);
  margin: 0 8px;
}

.message-text {
  padding: 10px 14px;
  background-color: var(--el-fill-color-light);
  border-radius: 0 8px 8px 8px;
  font-size: 14px;
  line-height: 1.5;
  text-align: left;
  word-break: break-all;
}
.message-status {
  font-size: 14px;
  line-height: 0;
}
.message-status-end {
  display: flex;
  align-items: flex-end;
  flex-direction: row-reverse;
}
.message-status-start {
  display: flex;
  align-items: flex-end;
}

.user-info-card {
  padding: 10px;

  .user-info-header {
    display: flex;
    flex-direction: column;
    align-items: center;
    margin-bottom: 15px;

    .user-info-name {
      margin-top: 10px;
      font-size: 16px;
      font-weight: 500;
    }
  }

  .user-info-content {
    .info-item {
      margin-bottom: 8px;
      font-size: 14px;
      display: flex;
      align-items: flex-start;

      .label {
        color: #909399;
        width: 80px;
        flex-shrink: 0;
      }
    }

    .expertise-tags {
      flex: 1;
      display: flex;
      flex-wrap: wrap;
      gap: 5px;

      .expertise-tag {
        margin-right: 5px;
        margin-bottom: 5px;
      }
    }
  }
}
.tool-bar {
  width: 100%;
  height: 40px;
  display: flex;
  justify-content: flex-end;
  align-items: center;
  padding-right: 20px;
  border-bottom: 1px solid var(--el-border-color-lighter);
  border-top: 1px solid var(--el-border-color-lighter);
}
</style>
